﻿using System.IO.Ports;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Oxage.Common;
using Oxage.Models;

namespace Oxage.Views
{
	public partial class ManualView : UserControl
	{
		private SerialPort port;
		private bool[] state = new bool[3];

		#region Constructor
		public ManualView()
		{
			InitializeComponent();
			this.Focusable = true;

			LayoutRoot.KeyDown += new KeyEventHandler(input_KeyDown);
			LayoutRoot.KeyUp += new KeyEventHandler(input_KeyUp);

			ViewModel.Axis1 = axis1;
			ViewModel.Axis2 = axis2;

			port = new SerialPort();
			port.PortName = "COM14";
			port.BaudRate = 9600;
			port.DataBits = 8;
			port.StopBits = StopBits.One;
			port.Parity = Parity.None;
			port.DataReceived += (sender, e) =>
			{
				try
				{
					int length = port.BytesToRead;
					byte[] data = new byte[length];
					int count = port.Read(data, 0, length);
					var model = Helper.BsonDeserialize<CncResponse>(data);
				}
				catch
				{
				}
			};
		}
		#endregion

		#region Public properties
		public ManualViewModel ViewModel
		{
			get
			{
				return this.DataContext as ManualViewModel;
			}
		}
		#endregion

		#region Protected methods
		protected void Command(char c)
		{
			port.Write(new byte[] { (byte)c }, 0, 1);
			Thread.Sleep(1);
		}

		protected void Command(char axis, bool dir, bool en)
		{
			switch (axis)
			{
				case 'x':
				case 'X':
					if (state[0] == en)
					{
						return;
					}
					state[0] = en;
					break;

				case 'y':
				case 'Y':
					if (state[1] == en)
					{
						return;
					}
					state[1] = en;
					break;

				case 'z':
				case 'Z':
					if (state[2] == en)
					{
						return;
					}
					state[2] = en;
					break;
			}

			var command = new CncCommand();
			command.axis = axis;
			command.dir = dir;
			command.en = en;

			var data = Helper.BsonSerialize(command);
			port.Write(data, 0, data.Length);
		}

		protected void Command(string line)
		{
			var command = new CncCodeLine() { line = line };
			var data = Helper.BsonSerialize(command);
			port.Write(data, 0, data.Length);
		}

		public class CncResponse
		{
			public int status { get; set; }
		}

		public class CncCommand
		{
			public CncCommand()
			{
				action = 1;
			}

			public int action { get; set; }
			public char axis { get; set; }
			public bool dir { get; set; }
			public bool en { get; set; }
			//public bool mode { get; set; }
			//public bool speed { get; set; }
		}

		public class CncCodeLine
		{
			public CncCodeLine()
			{
				action = 2;
			}

			public int action { get; set; }
			public string line { get; set; }
		}
		#endregion

		#region Event handlers
		private void input_KeyDown(object sender, KeyEventArgs e)
		{
			switch (e.Key)
			{
				case Key.A:
					port.Open();
					Command('!');
					break;

				case Key.S:
					port.Close();
					break;

				case Key.Left:
					Command('x', false, true);
					break;

				case Key.Right:
					Command('x', true, true);
					break;

				case Key.Up:
					Command('y', true, true);
					break;

				case Key.Down:
					Command('y', false, true);
					break;

				case Key.Add:
					Command('z', true, true);
					break;

				case Key.Subtract:
					Command('z', false, true);
					break;

				case Key.D1:
					Command("G01 X200 Y200 Z200");
					break;

				case Key.D2:
					Command("G01 X-200 Y-200 Z-200");
					break;

				case Key.D3:
					Command("G90");
					break;

				case Key.D4:
					Command("G91");
					break;
			}
		}

		private void input_KeyUp(object sender, KeyEventArgs e)
		{
			switch (e.Key)
			{
				case Key.Left:
					Command('x', false, false);
					break;

				case Key.Right:
					Command('x', true, false);
					break;

				case Key.Up:
					Command('y', true, false);
					break;

				case Key.Down:
					Command('y', false, false);
					break;

				case Key.Add:
					Command('z', true, false);
					break;

				case Key.Subtract:
					Command('z', false, false);
					break;
			}
		}

		#region Event handlers
		private void ToggleValueSign_Click(object sender, RoutedEventArgs e)
		{
			var button = sender as FrameworkElement;
			var model = button.Tag as AxisViewModel;
			if (model != null)
			{
				model.ToggleTargetValueSign();
			}
		}

		private void PreciseMove_Click(object sender, RoutedEventArgs e)
		{
			var button = sender as FrameworkElement;
			var model = button.Tag as AxisViewModel;
			if (model != null)
			{
				ViewModel.PreciseMove(model);
			}
		}

		private void ReferencePoint_Click(object sender, RoutedEventArgs e)
		{
			if (ViewModel.SelectedReferencePoint != null)
			{
				ViewModel.MoveToReference(ViewModel.SelectedReferencePoint);
			}
		}

		private void Relative_Click(object sender, RoutedEventArgs e)
		{
			var button = sender as FrameworkElement;
			var model = button.Tag as AxisViewModel;
			if (model != null)
			{
				model.AxisMovement = AxisMovement.Absolute;
			}
		}

		private void Absolute_Click(object sender, RoutedEventArgs e)
		{
			var button = sender as FrameworkElement;
			var model = button.Tag as AxisViewModel;
			if (model != null)
			{
				model.AxisMovement = AxisMovement.Relative;
			}
		}
		#endregion

		#endregion
	}
}
